package com.spring.component.link;

import java.util.ArrayList;
import java.util.List;

public abstract class Node<T> {
  protected Node<T> next;
  protected T value;


  public Node<T> getNext() {
    return next;
  }

  public T getValue() {
    return value;
  }

  public void setValue(T value) {
    this.value = value;
  }

  /**
   * 只输出当前节点
   *
   * @return
   */
  public String toNodeString() {
    return this.value == null ? null : this.value.toString();
  }

  /**
   * 遍历链表，如果有闭环，字符串末尾为->，末尾节点为闭环切入节点
   *
   * @return
   */
  public String toLinkString() {
    StringBuilder sb = new StringBuilder();
    List<Node> nodes = new ArrayList<>();
    recurNode(this, sb, nodes);
    return sb.substring(0, sb.length() - 2);
  }

  private void recurNode(Node node, StringBuilder sb, List<Node> nodes) {
    sb.append(node.value).append("->");
    if (!nodes.contains(node)) {
      // 可能存在闭环链表
      nodes.add(node);
      if (node.next != null) {
        recurNode(node.next, sb, nodes);
      }
    } else {
      sb.append("->");
    }
  }

  /**
   * 获取当前节点后面第i个节点
   * 
   * @param i
   * @return
   */
  public Node<T> getNext(int i) {
    if (i < 0) {
      return null;
    } else if (i == 0) {
      return this;
    } else {
      Node tmpNode = this.getNext();
      for (int j = 1; j < i; j++) {
        if (tmpNode == null) {
          return null;
        }
        tmpNode = tmpNode.getNext();
      }
      return tmpNode;
    }
  }

  /**
   * 设置当前节点的下一个节点并返回上一个节点
   * 
   * @param node
   * @return
   */
  public Node setNext(Node node) {
    Node n = this.next;
    this.next = node;
    return n;
  }

  /**
   * 获取最后一个节点，返回null，链表存在闭环
   * 
   * @return
   */
  public Node getLastNode() {
    if (isHavRing()) {
      return null;
    }
    Node n = this.next;
    if (n == null) {
      return this;
    }
    while (n.next != null) {
      n = n.next;
    }
    return n;
  }

  /**
   * 判断链表是否存在闭环
   * 
   * @return
   */
  public boolean isHavRing() {
    List<Node> nodes = new ArrayList<>();
    Node node = this;
    while (node != null && !nodes.contains(node)) {
      nodes.add(node);
      node = node.next;
    }
    return node != null;
  }

}
